package cn.xingzhe.monster.user.application.service.impl;

import cn.xingzhe.monster.user.application.converter.UserConverter;
import cn.xingzhe.monster.user.application.dto.UserDTO;
import cn.xingzhe.monster.user.application.service.UserApplicationService;
import cn.xingzhe.monster.user.domain.enums.CaptchaTypeEnum;
import cn.xingzhe.monster.user.domain.exception.InvalidCaptchaException;
import cn.xingzhe.monster.user.domain.exception.UserNotFoundException;
import cn.xingzhe.monster.user.domain.model.UserModel;
import cn.xingzhe.monster.user.domain.repository.UserRepository;
import cn.xingzhe.monster.user.domain.service.AuthenticationService;
import cn.xingzhe.monster.user.domain.service.CaptchaDomainService;
import cn.xingzhe.monster.user.domain.service.PasswordHasher;
import cn.xingzhe.monster.user.domain.service.PermissionDomainService;
import cn.xingzhe.monster.user.domain.service.UserDomainService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * 用户应用服务实现
 * 调用领域服务完成业务逻辑，操作领域模型
 *
 * @author System
 * @version 1.0.0
 * @since 2024-01-01
 */
@Service
public class UserApplicationServiceImpl implements UserApplicationService {

    private final UserRepository userRepository;
    private final UserConverter userConverter;
    private final PasswordHasher passwordHasher;
    private final CaptchaDomainService captchaDomainService;
    private final UserDomainService userDomainService;
    private final PermissionDomainService permissionDomainService;
    private final AuthenticationService authenticationService;

    public UserApplicationServiceImpl(UserRepository userRepository,
                                     UserConverter userConverter,
                                     PasswordHasher passwordHasher,
                                     CaptchaDomainService captchaDomainService,
                                     UserDomainService userDomainService,
                                     PermissionDomainService permissionDomainService,
                                     AuthenticationService authenticationService) {
        this.userRepository = userRepository;
        this.userConverter = userConverter;
        this.passwordHasher = passwordHasher;
        this.captchaDomainService = captchaDomainService;
        this.userDomainService = userDomainService;
        this.permissionDomainService = permissionDomainService;
        this.authenticationService = authenticationService;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public UserDTO registerByEmail(String email, String password, String captcha) {
        // 验证验证码
        if (!captchaDomainService.verifyCaptcha(email, captcha, CaptchaTypeEnum.REGISTER)) {
            throw InvalidCaptchaException.of();
        }

        // 验证注册信息（领域服务）
        userDomainService.validateRegistration(email, null, null);

        // 创建用户领域模型
        UserModel userModel = UserModel.registerByEmail(email, password, passwordHasher);
        
        // 保存用户
        userModel = userRepository.save(userModel);
        
        // 用户登录
        authenticationService.login(userModel.getId());
        
        return userConverter.toDTO(userModel);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public UserDTO registerByPhone(String phone, String password, String captcha) {
        // 验证验证码
        if (!captchaDomainService.verifyCaptcha(phone, captcha, CaptchaTypeEnum.REGISTER)) {
            throw InvalidCaptchaException.of();
        }

        // 验证注册信息（领域服务）
        userDomainService.validateRegistration(null, phone, null);

        // 创建用户领域模型
        UserModel userModel = UserModel.registerByPhone(phone, password, passwordHasher);
        
        // 保存用户
        userModel = userRepository.save(userModel);
        
        // 用户登录
        authenticationService.login(userModel.getId());
        
        return userConverter.toDTO(userModel);
    }

    @Override
    public UserDTO loginByUsername(String username, String password) {
        UserModel userModel = userRepository.findByUsername(username)
                .orElseThrow(() -> UserNotFoundException.of(username));

        // 使用领域服务验证登录（包含密码验证和状态检查）
        userDomainService.validateLogin(userModel, password, passwordHasher);

        // 用户登录
        authenticationService.login(userModel.getId());

        return userConverter.toDTO(userModel);
    }

    @Override
    public UserDTO loginByEmail(String email, String captcha) {
        // 验证验证码
        if (!captchaDomainService.verifyCaptcha(email, captcha, CaptchaTypeEnum.LOGIN)) {
            throw InvalidCaptchaException.of();
        }

        // 使用领域服务验证邮箱登录
        UserModel userModel = userDomainService.validateEmailLogin(email);

        // 用户登录
        authenticationService.login(userModel.getId());

        return userConverter.toDTO(userModel);
    }

    @Override
    public UserDTO loginByPhone(String phone, String captcha) {
        // 验证验证码
        if (!captchaDomainService.verifyCaptcha(phone, captcha, CaptchaTypeEnum.LOGIN)) {
            throw InvalidCaptchaException.of();
        }

        // 使用领域服务验证手机号登录
        UserModel userModel = userDomainService.validatePhoneLogin(phone);

        // 用户登录
        authenticationService.login(userModel.getId());

        return userConverter.toDTO(userModel);
    }

    @Override
    public List<String> getUserPermissions(String userId) {
        return permissionDomainService.getUserPermissionCodes(userId);
    }

    @Override
    public boolean checkPermission(String userId, String permissionCode) {
        return permissionDomainService.hasPermission(userId, permissionCode);
    }

    @Override
    public UserDTO getUserById(String userId) {
        UserModel userModel = userRepository.findById(userId)
                .orElseThrow(() -> UserNotFoundException.byId(userId));
        UserDTO userDTO = userConverter.toDTO(userModel);
        
        // 填充权限信息
        List<String> permissions = getUserPermissions(userId);
        userDTO.setPermissions(permissions);
        
        return userDTO;
    }

    @Override
    public String getCurrentToken() {
        return authenticationService.getCurrentToken();
    }

    @Override
    public String getCurrentUserId() {
        return authenticationService.getCurrentUserId();
    }

    @Override
    public void logout() {
        String userId = authenticationService.getCurrentUserId();
        if (userId != null) {
            authenticationService.logout(userId);
        }
    }
}

